package com.podmanager.RssFeed;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import android.util.Log;

/*
 * Parse an RSS Feed's XML File.  
 * A post list is created after the XML is parsed
 */
public class RSSParser {

	private String url;
	private String downloadFilePath;
	
	// subscription information
	private String subscriptionTitle;
	private String subscriptionLink;
	private String subscriptionDescription;
	private String descriptionLanguage;
	private String subscriptionPubDate;
	private String subscriptionLastBuildDate;
	private String subscriptionImageUrl;
	
	private List<RSSPost> episodeList;
	private DescriptionParser parser;
	
	public RSSParser() {
		episodeList = new ArrayList<RSSPost>();
	}
	
	/*
	 * url - the subscriptionLink to the RSS feed (i.e. the XML file)
	 * downloadPath - location of the downloaded XML file
	 */
	public RSSParser(String url, String downloadFilePath) {
		this();
		this.url = url;
		this.downloadFilePath = downloadFilePath;
	}
	
	public List<RSSPost> getPostList() {
		return episodeList;
	}
	
	/*
	 * Download the RSS XML file to a directory.
	 */
	public void downloadRSS() {
		try {
			URL website = new URL(url);
			URLConnection connection = website.openConnection();
			connection.connect();
			
			InputStream input = new BufferedInputStream(website.openStream());
			String fileName = downloadFilePath;
			OutputStream output = new FileOutputStream(fileName);
			
			byte[] data = new byte[1024];
			int count;
			while ((count = input.read(data)) != -1) 
				output.write(data, 0, count);
			
			output.flush();
			output.close();
			input.close();
			
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
			// Log.e("error", e.getMessage().toString());
		}
		catch (Exception e) {
			Log.e("error", e.getMessage().toString());
		}
	}
	
	/*
	 * Parse the RSS Feed's XML file.  A list of RSS posts is
	 * created after the parsing.
	 */
	public void parseRss() {
		File file = new File(downloadFilePath);
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		NodeList nodeList = null;
		
		try {
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document document = builder.parse(file);
			document.getDocumentElement().normalize();
			/*String rssNode =*/ document.getDocumentElement().getNodeName();
			// Log.d("", rssNode);
			nodeList = document.getElementsByTagName(RSSPost.SUBSCRIPTION);
			getChannelElements(nodeList);
			
			nodeList = document.getElementsByTagName(RSSPost.ITEM);
			getItemElements(nodeList, document);
			
			
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
	private void getChannelElements(NodeList nodeList) {
		Node firstNode = nodeList.item(0);
		
		if (firstNode.hasChildNodes()) {
			NodeList list = firstNode.getChildNodes();
			
			for(int i=0; i < list.getLength(); i++ ) {
				firstNode = list.item(i);
				setChannelInformation(firstNode);
			}
		}
	}

	private void setChannelInformation(Node firstNode) {
		if (firstNode.getNodeName().compareTo(RSSPost.TITLE) == 0) {
			//Log.d("Subscription Title:", firstNode.getTextContent()); 
			subscriptionTitle = firstNode.getTextContent();
		}
		else if(firstNode.getNodeName().compareTo(RSSPost.LINK) == 0) {
			//Log.d("Subscription Link:", firstNode.getTextContent()); 
			subscriptionLink = firstNode.getTextContent();
		}
		else if(firstNode.getNodeName().compareTo(RSSPost.DESCRIPTION) == 0) {
			//Log.d("Subscription Desc:", firstNode.getTextContent()); 
			subscriptionDescription = firstNode.getTextContent();
		}
		else if(firstNode.getNodeName().compareTo(RSSPost.LANGUAGE) == 0) {
			//Log.d("Subscription Language:", firstNode.getTextContent()); 
			descriptionLanguage = firstNode.getTextContent();
		}
		else if(firstNode.getNodeName().compareTo(RSSPost.PUB_DATE) == 0) {
			//Log.d("Subscription publish date: ", firstNode.getTextContent());
			this.subscriptionPubDate = firstNode.getTextContent();
		}
		else if(firstNode.getNodeName().compareTo(RSSPost.LASTBUILDDATE) == 0) {
			//Log.d("Subscription last build date: ", firstNode.getTextContent());
			this.subscriptionLastBuildDate = firstNode.getTextContent();
		}
		else if(firstNode.getNodeName().compareTo(RSSPost.IMAGE) == 0) {
			//Log.d("Subscription image url: ", firstNode.getTextContent());
			
			if (firstNode.hasChildNodes()) 
				setImageChildTags(firstNode);
			else 
				this.subscriptionImageUrl = firstNode.getTextContent();
		}
	}

	private void setImageChildTags(Node firstNode) {
		NodeList list = firstNode.getChildNodes();
		for(int i=0; i < list.getLength(); i++) {
			if (list.item(i).getNodeName().compareTo(RSSPost.SUB_IMAGE_URL) == 0) 
				this.subscriptionImageUrl = list.item(i).getTextContent();
			else if (list.item(i).getNodeName().compareTo(RSSPost.SUB_IMAGE_TITLE) == 0) 
				Log.d("sub image title:", list.item(i).getTextContent());
			else if (list.item(i).getNodeName().compareTo(RSSPost.SUB_IMAGE_LINK) == 0) 
				Log.d("sub image link:", list.item(i).getTextContent());
			else if (list.item(i).getNodeName().compareTo(RSSPost.SUB_IMAGE_WIDTH) == 0) 
				Log.d("sub image width:", list.item(i).getTextContent());
			else if (list.item(i).getNodeName().compareTo(RSSPost.SUB_IMAGE_HEIGHT) == 0) 
				Log.d("sub image height:", list.item(i).getTextContent());
		}
	}

	private void getItemElements(NodeList nodeList, Document document) {
		for (int i=0; i < nodeList.getLength(); i++) {
			Node firstNode = nodeList.item(i);

			if (firstNode.hasChildNodes()) {
				NodeList list = firstNode.getChildNodes();
				RSSPost rssPost = new RSSPost();
				
				setPostInformation(list, rssPost);

				setChannelInformation(rssPost);
				episodeList.add(rssPost);
			}
			
		}
	}

	private void setPostInformation(NodeList list, RSSPost rssPost) {
		for (int j = 0; j < list.getLength(); j++) 
			setPostInformationItem(list, rssPost, j);
	}

	private void setPostInformationItem(NodeList list, RSSPost rssPost, int j) {
		if (list.item(j).getNodeName().compareTo(RSSPost.TITLE) == 0) {
			//Log.d("Title:", list.item(j).getTextContent());
			rssPost.setTitle(list.item(j).getTextContent());
		}
		else if(list.item(j).getNodeName().compareTo(RSSPost.LINK) == 0) {
			//Log.d("Link:", list.item(j).getTextContent());
			//rssPost.setUrl(list.item(j).getTextContent());
		}
		else if (list.item(j).getNodeName().compareTo(RSSPost.DESCRIPTION) == 0) {
			//Log.d("Description:", list.item(j).getTextContent());
			parser = new DescriptionParser(list.item(j).getTextContent());
			try {
				parser.splitImageTag();
				rssPost.setDescription(parser.getDescription());
				rssPost.setThumbnailUrl(parser.getImageUrl());
			} catch (Exception e) {
				//Log.d("Debug RSS parsing", RSSPost.TITLE + " does not have <img> tag.");
				rssPost.setDescription(parser.getDescriptionTag());		// parser.getDescription());
				rssPost.setThumbnailUrl("not available");
			} 
			
		}
		else if (list.item(j).getNodeName().compareTo(RSSPost.PUB_DATE) == 0) {
			//Log.d("Pub date:", list.item(j).getTextContent());
			rssPost.setPubDate(list.item(j).getTextContent());
		} 
		else if (list.item(j).getNodeName().compareTo(RSSPost.GUID) == 0) {
			//Log.d("GUID:", list.item(j).getTextContent());
			rssPost.setEpisodeGuid(list.item(j).getTextContent());
		}
		else if (list.item(j).getNodeName().compareTo(RSSPost.ENCLOSURE) == 0) {
			Node node = list.item(j);
			if (node.hasAttributes()) {
				setEnclosureValues(rssPost, node);
			}
		}
	}

	private void setEnclosureValues(RSSPost rssPost, Node node) {
		NamedNodeMap nodeMap = node.getAttributes();
		for(int i=0; i < nodeMap.getLength(); i++) {
			if (nodeMap.item(i).getNodeName().compareTo(RSSPost.ENCLOSURE_URL) == 0) {
				//Log.d("enclosure podcast url:", nodeMap.item(i).getTextContent());
				rssPost.setUrl(nodeMap.item(i).getTextContent());
			}
			else if (nodeMap.item(i).getNodeName().compareTo(RSSPost.ENCLOSURE_LENGTH) == 0) {
				//Log.d("enclosure length:", nodeMap.item(i).getTextContent());
			}
			else if (nodeMap.item(i).getNodeName().compareTo(RSSPost.ENCLOSURE_TYPE) == 0) {
				//Log.d("enclosure file type:", nodeMap.item(i).getTextContent());
				rssPost.setEpisodeFileType(nodeMap.item(i).getTextContent());
			}
		}
	}

	private void setChannelInformation(RSSPost rssPost) {
		rssPost.setSubscriptionTitle(subscriptionTitle);
		rssPost.setSubscriptionLink(subscriptionLink);
		rssPost.setSubscriptionDescription(subscriptionDescription);
		rssPost.setSubscriptionLanguage(descriptionLanguage);
	}

	
	
	public String getSubscriptionTitle() {
		return subscriptionTitle;
	}

	public void setSubscriptionTitle(String subscriptionTitle) {
		this.subscriptionTitle = subscriptionTitle;
	}

	public String getSubscriptionLink() {
		return subscriptionLink;
	}

	public void setSubscriptionLink(String subscriptionLink) {
		this.subscriptionLink = subscriptionLink;
	}

	public String getSubscriptionDescription() {
		return subscriptionDescription;
	}

	public void setSubscriptionDescription(String subscriptionDescription) {
		this.subscriptionDescription = subscriptionDescription;
	}

	public String getDescriptionLanguage() {
		return descriptionLanguage;
	}

	public void setDescriptionLanguage(String descriptionLanguage) {
		this.descriptionLanguage = descriptionLanguage;
	}

	public String getSubscriptionPubDate() {
		return subscriptionPubDate;
	}

	public void setSubscriptionPubDate(String subscriptionPubDate) {
		this.subscriptionPubDate = subscriptionPubDate;
	}

	public String getSubscriptionLastBuildDate() {
		return subscriptionLastBuildDate;
	}

	public void setSubscriptionLastBuildDate(String subscriptionLastBuildDate) {
		this.subscriptionLastBuildDate = subscriptionLastBuildDate;
	}

	public String getSubscriptionImageUrl() {
		return subscriptionImageUrl;
	}

	public void setSubscriptionImageUrl(String subscriptionImageUrl) {
		this.subscriptionImageUrl = subscriptionImageUrl;
	}

	@Override
	public String toString() {
		StringBuilder output = new StringBuilder();
		
		for(RSSPost post : episodeList) {
			output.append(post.toString() + "\n\n");
		}
			
		return output.toString();
	}


	
}



